﻿using System;

using DKE_Kinect.Entwicklung.Core;
using DKE_Kinect.Entwicklung.Grafik.ControlManaging;
using DKE_Kinect.Entwicklung.PolyVox;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace DKE_Kinect.Entwicklung.Grafik
{
	/// <summary>
	/// Manager für XNA, wird genutzt um GUI, Kamera und Rendering zu steuern
	/// </summary>
	public class GraphicsManager : BaseManager
	{
		private readonly Color pMaskColor;

		/// <summary>
		/// Sprite Batch zum gesammelten Zeichnen von 2D Grafiken
		/// </summary>
		private SpriteBatch pSpriteBatch;
		/// <summary>
		/// GraphicsDevice für Zugriff auf die DirectX Grafikadapter
		/// </summary>
		private static GraphicsDeviceManager pGraphics;
		/// <summary>
		/// Logo für Splash Screen
		/// </summary>
		private Texture2D pLogo;
		/// <summary>
		/// Begrenzung des Logos
		/// </summary>
		private Rectangle pLogoBounds;
		/// <summary>
		/// Cursor für Navigation im 3D Raum
		/// </summary>
		private Cursor3D pCursor;
		/// <summary>
		/// Camera zur Darstellung des 3d Raumes
		/// </summary>
		private Camera3D pCamera;

		private ContainerManager pContainer;

		/// <summary>
		/// Gets the camera.
		/// </summary>
		public Camera3D Camera
		{
			get { return pCamera; }
		}
		/// <summary>
		/// Get the Cursor
		/// </summary>
		public Cursor3D Cursor
		{
			get { return pCursor; }
		}

		/// <summary>
		/// Gibt das Hauptmenü des Programms an.
		/// </summary>
		public PainectMenu MainMenu { get { return this.pContainer.MainMenu; } }

		/// <summary>
		/// Gibt das Quickmenü des Programms an.
		/// </summary>
		public QuickMenu QuickMenu { get { return this.pContainer.QuickMenu; } }

        /// <summary>
        /// Gibt das Farbwahlmenü des Programms an.
        /// </summary>
        public ColorMenu ColorMenu { get { return this.pContainer.ColorMenu; } }

        /// <summary>
        /// Gibt das Projektmenü des Programms an.
        /// </summary>
        public ProjectMenu ProjectMenu { get { return this.pContainer.ProjectMenu; } }

		/// <summary>
		/// Gibt die für dieses Projekt vorgesehene Farbe ( Magenta - R: 255, G: 0, B: 255 ) an, die in Bildern als Transparent markiert wird.
		/// </summary>
		public Color MaskColor { get { return this.pMaskColor; } }



		/// <summary>
		/// Konstruktor. Erstellt eine Instanz des Managers und weist die aktuelle Spielinstanz als Takgeber zu
		/// </summary>
		/// <param name="_game">Aktuelle Spielinstanz</param>
		/// <param name="_sBatch">Sprite Batch zum gesammleten Zeichnen von 2d Content</param>
		/// <param name="_gDManager">Zugriff auf die DirectX Grafik Schnittstelle</param>
		public GraphicsManager (Application _game, SpriteBatch _sBatch, GraphicsDeviceManager _gDManager)
			: base(_game)
		{
			this.pMaskColor = Color.Magenta;

			this.pSpriteBatch = _sBatch;

			GraphicsManager.pGraphics = _gDManager;
			this.pLogo = ContentManager.loadContent<Texture2D>("textures/logo");
			pLogoBounds = new Rectangle(GraphicsManager.pGraphics.PreferredBackBufferWidth - pLogo.Width / 5, 0, pLogo.Width / 5, pLogo.Height / 5);
			pCursor = new Cursor3D(new Vector3(0, 0, 0));

			pCamera = new Camera3D(_gDManager.GraphicsDevice.Viewport);
			pCamera.LookAt = new Vector3(0, 0, 0);
			pCamera.Position = new Vector3(0, 0, 75);

			// Menü intitalisieren:
			this.pContainer = new ContainerManager(GraphicsManager.pGraphics.GraphicsDevice, this.pParent.Window, this.pSpriteBatch);

			InitializeMainMenu();
			InitializeQuickMenu();
		}

		private readonly string[] pLabels = new string[]
			{
				"Pinsel",
				"Kamera",
				"Farbpalette",
				"Kamera Reset",
				"Radierer",
				"Screenshot",
				"Zurück"
			};
		/// <summary>
		/// Initialisiert das Hauptmenü.
		/// </summary>
		private void InitializeMainMenu ()
		{
			// Hauptmenü - Auswahl
			IMenu<MenuItem> MainMenu = this.pContainer.MainMenu;
			this.pContainer.MainMenu.SubItems.Add(new MenuItem("Projekt", MainMenu));
			this.pContainer.MainMenu.SubItems.Add(new MenuItem("Pinsel", MainMenu));
			this.pContainer.MainMenu.SubItems.Add(new MenuItem("Formen", MainMenu));
			this.pContainer.MainMenu.SubItems.Add(new MenuItem("Modus", MainMenu));
			this.pContainer.MainMenu.SubItems.Add(new MenuItem("Screenshot", new Action(delegate()
			{
				pParent.TakeScreenshot();
                StateManager.ReturnToPrevState();
			}
			), MainMenu));
			this.pContainer.MainMenu.SubItems.Add(new MenuItem("Programm beenden", new Action(delegate()
			{
				this.pParent.Exit();
			}
			), MainMenu));

			// Hauptmenü - Projekt
			MainMenu = this.pContainer.MainMenu.SubItems[0];
			MainMenu.SubItems.Add(new MenuItem("Neu", new Action(delegate()
			{
				Application.CurrentProjekt = new Projekt("NEW");
			}
			), MainMenu));
			MainMenu.SubItems.Add(new MenuItem("Laden", new Action(delegate()
			{
                StateManager.ReturnToPrevState();
                StateManager.ChangeState(eModus.loadmenu);
			}
			), MainMenu));
			MainMenu.SubItems.Add(new MenuItem("Speichern", new Action(delegate()
			{
                StateManager.ReturnToPrevState();
                StateManager.ChangeState(eModus.savemenu);
			}
			), MainMenu));

			// Hauptmenü - Pinsel
			MainMenu = this.pContainer.MainMenu.SubItems[1];
			MainMenu.SubItems.Add(new MenuItem("Pinseldicke", new Action(delegate()
			{
				if (Voxel.CurrentVoxel.getDensity() == 3)
				{
					Voxel.SetDensity(1);
					StateManager.LastDensity = 1;
				}
				else
				{
					Voxel.SetDensity((byte)(Voxel.CurrentVoxel.getDensity() + 1));
					StateManager.LastDensity += 1;
				}
			}
			), MainMenu));
			MainMenu.SubItems.Add(new MenuItem("Farbwahl", new Action(delegate()
			{
                StateManager.ReturnToPrevState();
                StateManager.ChangeState(eModus.colormenu);
			}
			), MainMenu));

			// Hauptmenü - Formen
			MainMenu = this.pContainer.MainMenu.SubItems[2];
			MainMenu.SubItems.Add(new MenuItem("Kugel", new Action(delegate()
			{
				Application.PolyvoxManager.SetSphereAt(pParent.GrafikManager.Cursor.Position, (10 * StateManager.LastDensity));
			}
			), MainMenu));
            MainMenu.SubItems.Add(new MenuItem("Quader", new Action(delegate()
            {
                Application.PolyvoxManager.SetBlockAt(pParent.GrafikManager.Cursor.Position, Vector3.Add(pParent.GrafikManager.Cursor.Position, new Vector3(5 * StateManager.LastDensity)));
            }
            ), MainMenu));

			// Hauptmenü - Modus
			MainMenu = this.pContainer.MainMenu.SubItems[3];
			MainMenu.SubItems.Add(new MenuItem("Zeichnen", new Action(delegate()
			{
				Voxel.SetDensity(StateManager.LastDensity);
				StateManager.ChangeState(eModus.painting);
			}
			), MainMenu));
			MainMenu.SubItems.Add(new MenuItem("Bewegen", new Action(delegate()
			{
				Voxel.SetDensity(StateManager.LastDensity);
				StateManager.MoveChangeMode = eModus.painting;
				StateManager.ChangeState(eModus.moving);
			}
			), MainMenu));
			MainMenu.SubItems.Add(new MenuItem("Kamera", new Action(delegate()
			{
                StateManager.ChangeState(eModus.cameraModeOrbital);
			}
			), MainMenu));
			MainMenu.SubItems.Add(new MenuItem("Radieren", new Action(delegate()
			{
				StateManager.LastDensity = Voxel.CurrentVoxel.getDensity();
				Voxel.SetDensity((byte)0);
				StateManager.ChangeState(eModus.eraser);
			}
			), MainMenu));
		}

		/// <summary>
		/// Initiailisiert das Quickmenü.
		/// </summary>
		private void InitializeQuickMenu ()
		{
			IMenu<QuickMenuItem> QuickMenu = this.pContainer.QuickMenu;

			for (int i = 0; i < this.pLabels.Length - 1; i++)
			{
				QuickMenuItem item = new QuickMenuItem(this.pLabels[i], QuickMenu);
				item.Icon = ContainerRessources.GetIcons()[i];
				item.ActivationType = ActivationType.OwnDelegate;
				QuickMenu.SubItems.Add(item);
			}

			QuickMenu.SubItems[0].Action = new Action(delegate()
            {
	            if (Voxel.CurrentVoxel.getDensity() == 3)
	            {
		            Voxel.SetDensity(1);
		            StateManager.LastDensity = 1;
	            }
	            else
	            {
		            Voxel.SetDensity((byte)(Voxel.CurrentVoxel.getDensity() + 1));
		            StateManager.LastDensity += 1;
	            }
            });

			QuickMenu.SubItems[1].Action = new Action(delegate()
			{
                if (StateManager.PrevMode != eModus.cameraModeOrbital && StateManager.PrevMode != eModus.cameraModeLook)
				{
                    // Umschalten des Icons (+evtl. Reset des Radier-Icons)
                    QuickMenu.SubItems[4].Icon = ContainerRessources.GetIcons()[4];
                    QuickMenu.SubItems[1].Icon = ContainerRessources.GetIcons()[10];
					StateManager.PrevMode = eModus.cameraModeOrbital;
				}
				else
				{
                    QuickMenu.SubItems[1].Icon = ContainerRessources.GetIcons()[1];
					Voxel.SetDensity(StateManager.LastDensity);
					StateManager.MoveChangeMode = eModus.painting;
					StateManager.PrevMode = eModus.moving;
				}
			});

			QuickMenu.SubItems[2].Action = new Action(delegate()
			{
                StateManager.ReturnToPrevState();
                StateManager.PrevMode = eModus.colormenu;
			});

			QuickMenu.SubItems[3].Action = new Action(delegate()
			{
				pCamera.LookAt = new Vector3(0, 0, 0);
				pCamera.Position = new Vector3(0, 0, 75);
				pCursor.SetTo(new Vector3(0, 0, 0));
			});

			QuickMenu.SubItems[4].Action = new Action(delegate()
			{
				if (StateManager.PrevMode != eModus.eraser)
				{
                    // Umschalten des Icons (+evtl. Reset des Kamera-Icons)
                    QuickMenu.SubItems[1].Icon = ContainerRessources.GetIcons()[1];
                    QuickMenu.SubItems[4].Icon = ContainerRessources.GetIcons()[11];

					StateManager.LastDensity = Voxel.CurrentVoxel.getDensity();
					Voxel.SetDensity((byte)0);
					StateManager.PrevMode = eModus.eraser;
				}
				else
				{
                    QuickMenu.SubItems[4].Icon = ContainerRessources.GetIcons()[4];
					Voxel.SetDensity(StateManager.LastDensity);
					StateManager.MoveChangeMode = eModus.painting;
					StateManager.PrevMode = eModus.moving;
				}

			});

			QuickMenu.SubItems[5].Action = new Action(delegate()
			{
				pParent.TakeScreenshot();
			});

		}


		/// <summary>
		/// Draw Zyklus: Wird kontinuirlich getrigger von der Game Klasse. Dient zum zeichnen des Screens
		/// </summary>
		/// <param name="gameTime">Spielzeit Objekt mit Zeit seit letzem Update, Gesamtlaufzeit u.Ä.</param>
		public override void Draw (Microsoft.Xna.Framework.GameTime gameTime)
		{
			pCursor.Draw(gameTime, pCamera);
			//Save States
		}


		/// <summary>
		/// Draw - Ereignisse, die auf einem SpriteBatch, also 2D, erfolgen.
		/// </summary>
		/// <param name="gameTime"></param>
		/// <param name="batch"></param>
		public void DrawSpriteBatch (Microsoft.Xna.Framework.GameTime gameTime, SpriteBatch batch)
		{
			batch.Draw(pLogo, pLogoBounds, Color.Black);
			StatusInfo.DrawStatus(batch);


            switch(StateManager.CurrMode)
            {
                case eModus.mainmenu:
                case eModus.quickmenu:
                case eModus.colormenu:
                case eModus.savemenu:
                case eModus.loadmenu:
				    this.pContainer.Draw(gameTime, batch);
                break;
            }
		}


		/// <summary>
		/// Update Zyklus: Wird kontinuirlich von der Game Klasse getriggert um Logik zu berechnen
		/// </summary>
		/// <param name="gameTime">Spielzeit Objekt mit Zeit seit letzem Update, Gesamtlaufzeit u.Ä.</param>
		public override void Update (Microsoft.Xna.Framework.GameTime gameTime)
		{
            switch(StateManager.CurrMode)
            {
                case eModus.mainmenu:
                    this.pContainer.MainMenu.Visible = true;
                    this.pContainer.QuickMenu.Visible = false;
                    this.pContainer.ColorMenu.Visible = false;
                    this.pContainer.ProjectMenu.Visible = false;
                    break;
                case eModus.quickmenu:
                    this.pContainer.MainMenu.Visible = false;
                    this.pContainer.QuickMenu.Visible = true;
                    this.pContainer.ColorMenu.Visible = false;
                    this.pContainer.ProjectMenu.Visible = false;
                    break;
                case eModus.colormenu:
                    this.pContainer.MainMenu.Visible = false;
				    this.pContainer.QuickMenu.Visible = false;
                    this.pContainer.ColorMenu.Visible = true;
                    this.pContainer.ProjectMenu.Visible = false;
                    break;
                case eModus.savemenu:
                    this.pContainer.MainMenu.Visible = false;
				    this.pContainer.QuickMenu.Visible = false;
                    this.pContainer.ColorMenu.Visible = false;
                    this.pContainer.ProjectMenu.Visible = true;
                    break;
                case eModus.loadmenu:
                    this.pContainer.MainMenu.Visible = false;
				    this.pContainer.QuickMenu.Visible = false;
                    this.pContainer.ColorMenu.Visible = false;
                    this.pContainer.ProjectMenu.Visible = true;
                    break;
            
                default:
				    this.pContainer.MainMenu.Visible = false;
				    this.pContainer.QuickMenu.Visible = false;
                    this.pContainer.ColorMenu.Visible = false;
                    this.pContainer.ProjectMenu.Visible = false;

                    break;
			}

			this.pContainer.Update(gameTime);
		}
	}
}
